/*
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdint.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "usb_ext_screen.h"
#include "usbd_core.h"
#include "usb_public.h"
#include "work_status_setting.h"
#include "lcd.h"
#include "tusb_residual.h"
#include "esp_jtag_vendord.h"
static const char *TAG = "app_usb";

/**********************************USB描述符配置******************************************/
#define USB_EXT_SCREEN_DESCRIPTOR_LEN        (9 + 7 + 7)
#define USB_EXT_SCREEN_CONFIG_DESC_SIZE      (9 + USB_EXT_SCREEN_DESCRIPTOR_LEN)

/*
    ESP内置JTAG子类和协议分别是0xFF和0x01。
    但是TinyUSB默认值是0x00。
    为了在不修改TinyUSB的情况下使用相同的协议，我们在这里重新定义厂商描述符。
*/
// 接口号、字符串索引、输出端点地址、输入端点地址、端点大小
#define TUD_VENDOR_EUB_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize)                                                                                  \
    /* 接口描述符 */                                                                                                                                         \
    9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, EUB_VENDORD_IFACE_SUBCLASS, EUB_VENDORD_IFACE_PROTOCOL, _stridx, /* 输出端点描述符 */ \
        7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,                                                       /* 输入端点描述符 */ \
        7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0


static const uint8_t usb_ext_screen_device_descriptor_default[] = {
    USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0, 0, 0, 0x303A, 0x2986, 0x0101, 0x01),
};
static const uint8_t usb_ext_screen_config_descriptor[] = {
    // 配置描述符
    USB_CONFIG_DESCRIPTOR_INIT(USB_EXT_SCREEN_CONFIG_DESC_SIZE, USB_EXT_SCREEN_INF_NUM, 0x01, USB_CONFIG_BUS_POWERED, 100),
    // 厂商自定义接口描述符(接口号、字符串索引、输出端点地址、输入端点地址、端点大小)
    TUD_VENDOR_EUB_DESCRIPTOR(0, 4, EPNUM_VENDOR, 0x80 | EPNUM_VENDOR, 64),
};

char *usb_ext_screen_string_descriptors[] = {
    (char[]){ 0x09, 0x04 },         // 0: 支持的语言(英语0x0409)
    "MIDUO",                        // 1: 制造商字符串
    "MDLink", // 2: 产品名称
    "09-2025",                      //序列号
    /*将 `Ejpg6` 修改为所需的图片质量，数字越大质量越高，同样的一帧图像占用内存更多。*/
    "esp32p4udisp0_R320x240_Ejpg6", // 4: 供应商自定义接口字符串
};

//设备描述符回调函数
static const uint8_t *usb_ext_screen_device_descriptor_callback(uint8_t speed)
{
    (void)speed;
    return usb_ext_screen_device_descriptor_default;
}

//配置描述符回调函数
static uint8_t *usb_ext_screen_config_descriptor_callback(uint8_t speed)
{
    (void)speed;
    return usb_ext_screen_config_descriptor;
}
static const char *usb_ext_screen_string_descriptor_callback(uint8_t speed, uint8_t index)
{
    (void)speed;

    if (index >= (sizeof(usb_ext_screen_string_descriptors) / sizeof(char *))) {
        return NULL;
    }
    return usb_ext_screen_string_descriptors[index];
}


// USB 描述符配置结构体
const struct usb_descriptor usb_ext_screen_descriptor = {
    // 设备描述符回调函数（获取设备的基本信息，如VID、PID、设备类等）
    .device_descriptor_callback = usb_ext_screen_device_descriptor_callback,
    // 配置描述符回调函数（定义USB设备的配置、接口、端点等）
    .config_descriptor_callback = usb_ext_screen_config_descriptor_callback,
    // 设备品质描述符回调函数（可选，用于返回设备品质描述符）
    .device_quality_descriptor_callback = usb_device_quality_descriptor_callback_default,
    // 其他速率配置描述符回调函数（用于USB高速/全速/低速兼容性描述）
    //.other_speed_descriptor_callback = esp_jtag_other_speed_config_descriptor_callback,
    // 字符串描述符回调函数（返回厂商、产品、序列号等字符串信息）
    .string_descriptor_callback = usb_ext_screen_string_descriptor_callback,
    // BOS（Binary Device Object Store）描述符（用于USB 2.1+，支持扩展能力描述）
    .bos_descriptor = &bos_desc,
    // Microsoft OS 2.0描述符（用于Windows兼容性，如自动加载驱动）
    .msosv2_descriptor = &msosv2_desc,
};
/**********************************USB描述符配置 END******************************************/

int usb_ext_screen_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
    ESP_LOGI(TAG, "call usb_ext_screen_class_interface_request_handler\n");
    return 0;
}
int usb_ext_screen_vendor_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
    ESP_LOGI(TAG, "call usb_ext_screen_vendor_handler\n");
    return 0;
}
struct usbd_interface *usbd_ext_screen_init_intf(uint8_t busid, struct usbd_interface *intf)
{
    (void)busid;

    intf->class_interface_handler = usb_ext_screen_class_interface_request_handler;
    intf->class_endpoint_handler = NULL;
    intf->vendor_handler = usb_ext_screen_vendor_handler;
    intf->notify_handler = NULL;

    return intf;
}
/*在 usb_ext_screen_vendor.c中实现端点回调函数*/
void usb_ext_screen_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes);
void usb_ext_screen_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes);
//usb接口
static struct usbd_interface usb_ext_screen_intf;

/*在esp_jtag_vendord.c中实现端点回调函数*/
struct usbd_endpoint usb_ext_screen_out_ep = {
    .ep_addr = EPNUM_VENDOR,
    .ep_cb = usb_ext_screen_out_callback
};
struct usbd_endpoint usb_ext_screen_in_ep = {
    .ep_addr = 0x80 | EPNUM_VENDOR,
    .ep_cb = usb_ext_screen_in_callback
};
esp_err_t usb_ext_screen_init(uint8_t busid, uint32_t reg_base)
{
    esp_err_t ret = ESP_OK;
    set_work_status(USB_EXT_SCREEN_WORK);
    usbd_desc_register(busid, &usb_ext_screen_descriptor);

    /*!< usb副屏 */
    usbd_add_interface(0, usbd_ext_screen_init_intf(0, &usb_ext_screen_intf));
    usbd_add_endpoint(0, &usb_ext_screen_out_ep);
    usbd_add_endpoint(0, &usb_ext_screen_in_ep);
    extern void usbd_event_handler(uint8_t busid, uint8_t event);
    // usbd_event_handler在dap.main.c中定义
    usbd_initialize(busid, reg_base, usbd_event_handler);


    ret = app_vendor_init();
    ESP_RETURN_ON_FALSE(ret == ESP_OK, ESP_FAIL, TAG, "app_vendor_init failed");


    return ret;
}
esp_err_t usb_ext_screen_deinit(uint8_t busid)
{
    usbd_deinitialize(busid);     // 反初始化USB设备
    usb_esp_jtag_serial_enable(); // 启用JTAG串口
    //删除传输任务,释放帧缓冲区
    app_vendor_deinit();
    return ESP_OK;
}